import collections
import datetime
import logging
import time

from absl import app, flags
from slackclient import SlackClient

from coin.base.datetime_util import to_datetime
from coin.strategy.tool.monitor.log_parser_runner import check_utc
from coin.strategy.tool.monitor.run import process_log


def _parse_time_from_result(result, key):
  parsed = None
  value = result[key]
  if value == '':
    return parsed
  if key == 'last_log':
    assert len(value) == 8
  elif key == 'fill_2':
    assert len(value) == 9 and value[-1] in ('+', '-')
    value = value[:-1]
  else:
    raise ValueError('Unknown key: %s' % key)
  splitted = value.split(':')
  assert len(splitted) == 3
  parsed = [int(entry) for entry in splitted]
  return parsed


def _get_abnormal_strats_by_last_log(results):
  abnornals = []
  for result in results:
    parsed = _parse_time_from_result(result, 'last_log')
    if parsed is None:
      continue
    hour, minute, sec = parsed
    if minute >= 5:
      abnornals.append(result)
  return abnornals


def _get_abnormal_strats_by_last_fill(results):
  abnornals = []
  """
  for result in results:
    parsed = _parse_time_from_result(result, 'fill_2')
    if parsed is None:
      continue
    hour, minute, sec = parsed
    name = result['name']
    if name.startswith('unhedged_mm') and hour >= 1:
      abnornals.append(result)
  """
  return abnornals


class StratMonitor(object):
  def __init__(self):
    self._prev_abnormal_strats = set()

  def update_by_log_result(self, strategy_group, results, current_time):
    abnormal_1 = _get_abnormal_strats_by_last_log(results)
    abnormal_2 = _get_abnormal_strats_by_last_fill(results)
    token = 'xoxb-95415286342-Ri43thLnJimEWuQnIK0oBOkR'
    sc = SlackClient(token)
    abnormals = abnormal_1 + abnormal_2
    abnormals_per_owner = collections.defaultdict(list)
    abnormal_strats = set()
    for result in abnormals:
      if result['name'].startswith('RETIRED'):
        continue
      abnormal_strats.add((result['owner'], result['name']))
      abnormals_per_owner[result['owner']].append(result['name'])

    if len(abnormals) > 0 and self._prev_abnormal_strats != abnormal_strats:
      messages = []
      for owner, names in abnormals_per_owner.items():
        strategy_group = 'All' if strategy_group is None else strategy_group
        message = '\nstrategy_group: %s, owner: %s, # abnormal strats: %d (%s UTC)' % (
            strategy_group, owner, len(names), current_time)
        messages.append(message)
        for name in names:
          messages.append('  %s' % name)

      msgslk = '```%s```' % '\n'.join(messages)

      sc.api_call('chat.postMessage',
                  channel='coin_ops_monitor',
                  text=msgslk,
                  icon_emoji=':suzy:',
                  username='suzy')

    self._prev_abnormal_strats = abnormal_strats


def main(argv):
  FLAGS = flags.FLAGS

  assert check_utc(), 'Invalid timezone'
  duration = FLAGS.duration
  strategy_group = FLAGS.strategy_group
  assert duration >= 0
  start_time = datetime.datetime.now()
  strat_monitor = StratMonitor()

  while True:
    current_time = datetime.datetime.now()
    today_dt = to_datetime(current_time.date())
    if current_time - today_dt == datetime.timedelta():
      current_time -= datetime.timedelta(microseconds=1)
      today_dt = to_datetime(current_time.date())

    results = process_log(strategy_group, current_time)

    strat_monitor.update_by_log_result(strategy_group, results, current_time)

    duration_delta = datetime.timedelta(seconds=duration)
    if datetime.datetime.now() - start_time > duration_delta:
      break
    time.sleep(5)


if __name__ == '__main__':
  logging.basicConfig(level='DEBUG', format='%(levelname)8s %(asctime)s %(name)s] %(message)s')

  flags.DEFINE_integer('strategy_group', None, 'Strategy group to parse')
  flags.DEFINE_integer('duration', 0, 'duration in seconds')
  app.run(main)
